package elicecn.util.encrypt;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.security.NoSuchAlgorithmException;

/**
 * {@link Encrypt}接口的默认实现。它没有实现任何算法，仅实现了消息摘要计算过程方法。
 * 
 * @author 屹砾
 * @email eli.wuhan@gmail.com
 * @time 2009-3-1
 */
public abstract class EncryptBase implements Encrypt, Serializable {
	private static final long serialVersionUID = -6860419071975797082L;
	protected static final int BUFFER_SIZE = 8192;

	/**
	 * 使用指定的输入流进行计算。
	 * 
	 * @param stream
	 *            输入流
	 * @return 存放结果的十六进制数字字符串。
	 * @throws IOException
	 *             如果发生 I/O 错误(在使用输入流进行计算时可能抛出此异常)。
	 */
	protected abstract String calculate(InputStream stream) throws IOException;

	/**
	 * 使用指定的输入流进行计算。
	 * 
	 * @param stream
	 *            输入流
	 * @return 存放结果的十六进制数字字符串。
	 * @throws IOException
	 *             如果发生 I/O 错误
	 */
	public String calc(InputStream stream) throws IOException {
		return calculate(stream);
	}

	/**
	 * 使用指定的字符数组和消息算法进行计算。
	 * 
	 * @param bytes
	 *            字符数组
	 * @return 存放结果的十六进制数字字符串。
	 */
	public String calc(byte[] bytes) {
		try {
			return calc(new ByteArrayInputStream(bytes));
		} catch (IOException e) {
			// 没有使用到IO流，此异常永远不会产生。
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 使用指定的文件进行计算。
	 * 
	 * @param file
	 *            文件
	 * @return 存放结果的十六进制数字字符串。
	 * @throws FileNotFoundException
	 *             如果该文件不存在，或者它是一个目录，而不是一个常规文件，抑或因为其他某些原因而无法打开进行读取。
	 * @throws IOException
	 *             如果发生 I/O 错误
	 */
	public String calc(File file) throws FileNotFoundException, IOException {
		return calc(new FileInputStream(file));
	}

	/**
	 * 使用指定的字符串进行摘要计算。
	 * 
	 * @param string
	 *            字符串
	 * @return 存放结果的十六进制数字字符串。
	 */
	public String calc(String string) {
		return calc(string.getBytes());
	}

	/**
	 * 获取计算数据流的 CRC-32 的对象。
	 * 
	 * @return Encrypt
	 */
	public static Encrypt getCRC32Algorithm() {
		return new CRC32();
	}

	/**
	 * 获取基于MD2算法的消息摘要对象。
	 * 
	 * @return Encrypt
	 */
	public static Encrypt getMD2Algorithm() {
		return getAlgorithm("MD2");
	}

	/**
	 * 获取基于MD5算法的消息摘要对象。
	 * 
	 * @return Encrypt
	 */
	public static Encrypt getMD5Algorithm() {
		return getAlgorithm("MD5");
	}

	/**
	 * 获取基于SHA1算法的消息摘要对象。
	 * 
	 * @return Encrypt
	 */
	public static Encrypt getSHA1Algorithm() {
		return getAlgorithm("SHA1");
	}

	/**
	 * 获取指定算法的消息摘要对象。
	 * 
	 * @param algorithm
	 * @return encrypt
	 */
	public static Encrypt getAlgorithm(String algorithm) {
		Encrypt encrypt;
		try {
			encrypt = new MessageDigest(java.security.MessageDigest
					.getInstance(algorithm));
		} catch (NoSuchAlgorithmException e) {
			throw new IllegalStateException();
		}
		return encrypt;
	}
}
